﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Ink;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation;

namespace LetsGoToSchool
{
    /// <summary>
    /// Interaction logic for DoodlePalette.xaml
    /// </summary>
    public partial class DoodlePalette : UserControl
    {
        /// <summary>
        /// The most recent stroke (used for undo operations).
        /// </summary>
        private Stack<Stroke> _undoStack = new Stack<Stroke>();
        private Stack<Stroke> _redoStack = new Stack<Stroke>();
        private SurfaceInkCanvas _drawingCanvas;

        // Cached button images
        private readonly Image _drawButtonImage;

        public DoodlePalette()
        {
            InitializeComponent();

            _drawButtonImage = Utils.loadImage("pack://application:,,,/Resources/" + "Draw.png");
            _drawButtonImage.Height = 50;
            _drawButtonImage.Width = 50;
        }

        public void setDrawingCanvas(SurfaceInkCanvas dc)
        {
            _drawingCanvas = dc;
            _drawingCanvas.StrokeCollected += OnStrokeCollected;
        }

        /// <summary>
        /// Handles the OnStrokeCollected event for SurfaceInkCanvas.
        /// </summary>
        /// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
        /// <param name="args">The arguments for the event.</param>
        private void OnStrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs args)
        {
            _undoStack.Push(args.Stroke);
        }

        /// <summary>
        /// Handles the click event for the undo button.
        /// </summary>
        /// <param name="sender">The button that raised the event.</param>
        /// <param name="e">The arguments for the event.</param>
        void UndoClicked(object sender, RoutedEventArgs e)
        {
            if (_undoStack.Count != 0)
            {
                Stroke stroke = _undoStack.Pop();
                _drawingCanvas.Strokes.Remove(stroke);
                _redoStack.Push(stroke);
            }
        }

        /// <summary>
        /// Handles the click event for the redo button.
        /// </summary>
        /// <param name="sender">The button that raised the event.</param>
        /// <param name="e">The arguments for the event.</param>
        void RedoClicked(object sender, RoutedEventArgs e)
        {
            if (_redoStack.Count != 0)
            {
                Stroke stroke = _redoStack.Pop();
                _drawingCanvas.Strokes.Add(stroke);
                _undoStack.Push(stroke);
            }
        }

        /// <summary>
        /// Toggles the edit mode of a SurfaceInkCanvas between EraseByPoint and Ink.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="args">The arguments for the event.</param>
        private void EditModeClicked(object sender, RoutedEventArgs args)
        {
            SurfaceButton button = (SurfaceButton)sender;
            if (_drawingCanvas.EditingMode == SurfaceInkEditingMode.Ink)
            {
                _drawingCanvas.EditingMode = SurfaceInkEditingMode.EraseByPoint;

                // Load the new button image
                button.Content = _drawButtonImage;
            }
            else
            {
                _drawingCanvas.EditingMode = SurfaceInkEditingMode.Ink;

                // Load the new button image
                button.Content = _eraseButtonImage;
            }
        }

        /// <summary>
        /// Handles the tap event for the current color indicator.
        /// </summary>
        /// <param name="sender">The color wheel.</param>
        /// <param name="args">The arguments for the event.</param>
        private void OnCurrentColorTap(object sender, ContactEventArgs args)
        {
            // Replace the current color botton with the color wheel
            ColorWheel.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Handles the tap event for the color wheel.
        /// </summary>
        /// <param name="sender">The color wheel.</param>
        /// <param name="args">The arguments for the event.</param>
        private void OnColorWheelContactUp(object sender, ContactEventArgs args)
        {
            // Set the color on the CurrentColor indicator and on the SurfaceInkCanvas
            Color color = this.GetPixelColor(args.Contact);

            //if color.A ==0 means hit the transparent part of the color wheel, 
            //in which case, current color stays the same
            if (color.A != 0)
            {
                _drawingCanvas.DefaultDrawingAttributes.Color = color;
                CurrentColor.Fill = new SolidColorBrush(color);
            }

            // Set editing mode to ink
            _drawingCanvas.EditingMode = SurfaceInkEditingMode.Ink;

            // Update the button image
            EditModeButton.Content = _eraseButtonImage;

            // Replace the color wheel with the current color button
            ColorWheel.Visibility = Visibility.Hidden;
        }

        /// <summary>
        /// Handles the ContactDownEvent for the color wheel and the current color indicator.
        /// </summary>
        /// <param name="sender">The color wheel that raised the event.</param>
        /// <param name="args">The arguments for the event.</param>
        private void OnColorSelectionPreviewContactDown(object sender, ContactEventArgs args)
        {
            // Capture the contact and handle the event 
            IInputElement element = sender as IInputElement;
            if (element != null && Contacts.CaptureContact(args.Contact, element))
            {
                args.Handled = true;
            }
        }

        /// <summary>
        /// Gets the color of a specific pixel.
        /// </summary>
        /// <param name="pt">The point from which to get a color.</param>
        /// <returns>The color of the point.</returns>
        private System.Windows.Media.Color GetPixelColor(Contact contact)
        {
            // Translate the point according to whatever transforms are on the color wheel.
            double scale = 256/ColorWheel.Width;
            Point rawPoint = contact.GetPosition(ColorWheel);
            Point transformedPoint = new Point(rawPoint.X * scale, rawPoint.Y*scale);
            // The point is outside the color wheel. Return black.
            if (transformedPoint.X < 0 || transformedPoint.X >= 256 ||
                transformedPoint.Y < 0 || transformedPoint.Y >= 256)
            {
                return Colors.Transparent;
            }

            // The point is inside the color wheel. Find the color at the point.
            if (ColorWheel.Source as BitmapSource != null)
            {
                CroppedBitmap cb = new CroppedBitmap(ColorWheel.Source as BitmapSource, new Int32Rect((int)transformedPoint.X, (int)transformedPoint.Y, 1, 1));
                byte[] pixels = new byte[4];
                cb.CopyPixels(pixels, 4, 0);
                return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
            }
            return Colors.Transparent;
        }
    }
}
